#include <windows.h>

#define HAVE_BOOLEAN
#define XMD_H

#include <stdio.h>
#include "video.h"

#include "libmng.h"
#include "VBitmap.h"
#include "Resample.h"
#include "cpuaccel.h"

enum { e_INTERPOLATED, e_DECIMATED, e_FULL } g_eMode = e_INTERPOLATED;

Resampler::eFilter	g_eFilter = Resampler::kCubicInterp;

mng_uint32			g_uiRefreshRate;
mng_uint32			g_uiImageWidth;
mng_uint32			g_uiImageHeight;
mng_uint32			g_uiTimer;
FILE				*g_poMNGFile = 0;

char				g_acCodec[5] = "xvid";
int					g_bConfig = 0;

int					g_bResample = 0;
mng_uint32			g_uiResampledWidth;
mng_uint32			g_uiResampledHeight;
mng_uint32			g_uiCanvasWidth;
mng_uint32			g_uiCanvasHeight;

VBitmap				*g_poSrc;
VBitmap				*g_poDst;
Resampler			g_oResampler;

unsigned char		*g_pcCanvas0 = 0, *g_pcCanvas1 = 0, *g_pcCurrentCanvas = 0, *g_pcResampledCanvas = 0;
char				*g_pcMNGFileName = 0;
char				*g_pcAVIFileName = 0;
unsigned int		g_uiFrame;

/*
 =======================================================================================================================
 =======================================================================================================================
 */

int bMNGError(mng_retcode _iRetCode)
{
	if(_iRetCode != MNG_NOERROR)
	{
		/*~~~~~~~~~~~~~~~~~*/
		char	*szError = 0;
		/*~~~~~~~~~~~~~~~~~*/

		switch(_iRetCode)
		{
		case MNG_OUTOFMEMORY:		szError = "MNG_OUTOFMEMORY : oops, buy some megabytes!"; break;
		case MNG_INVALIDHANDLE:		szError = "MNG_INVALIDHANDLE : call mng_initialize first"; break;
		case MNG_NOCALLBACK:		szError = "MNG_NOCALLBACK : set the callbacks please"; break;
		case MNG_UNEXPECTEDEOF:		szError = "MNG_UNEXPECTEDEOF : what'd ya do with the data?"; break;
		case MNG_ZLIBERROR:			szError = "MNG_ZLIBERROR : zlib burped"; break;
		case MNG_JPEGERROR:			szError = "MNG_JPEGERROR : jpglib complained"; break;
		case MNG_LCMSERROR:			szError = "MNG_LCMSERROR : little cms stressed out"; break;
		case MNG_NOOUTPUTPROFILE:	szError = "MNG_NOOUTPUTPROFILE : no output-profile defined"; break;
		case MNG_NOSRGBPROFILE:		szError = "MNG_NOSRGBPROFILE : no sRGB-profile defined"; break;
		case MNG_BUFOVERFLOW:		szError = "MNG_BUFOVERFLOW : zlib output-buffer overflow"; break;
		case MNG_FUNCTIONINVALID:	szError = "MNG_FUNCTIONINVALID : ay, totally inappropriate"; break;
		case MNG_OUTPUTERROR:		szError = "MNG_OUTPUTERROR : disk full ?"; break;
		case MNG_JPEGBUFTOOSMALL:	szError = "MNG_JPEGBUFTOOSMALL : can't handle buffer overflow"; break;
		case MNG_NEEDMOREDATA:		szError = "MNG_NEEDMOREDATA : I'm hungry, give me more"; break;
		case MNG_NEEDTIMERWAIT:		szError = "MNG_NEEDTIMERWAIT : Sleep a while then wake me"; break;
		case MNG_NEEDSECTIONWAIT:	szError = "MNG_NEEDSECTIONWAIT : just processed a SEEK"; break;
		case MNG_LOOPWITHCACHEOFF:	szError = "MNG_LOOPWITHCACHEOFF : LOOP when playback info off"; break;
		case MNG_DLLNOTLOADED:		szError = "MNG_DLLNOTLOADED : late binding failed"; break;
		case MNG_APPIOERROR:		szError = "MNG_APPIOERROR : application I/O error"; break;
		case MNG_APPTIMERERROR:		szError = "MNG_APPTIMERERROR : application timing error"; break;
		case MNG_APPCMSERROR:		szError = "MNG_APPCMSERROR : application CMS error"; break;
		case MNG_APPMISCERROR:		szError = "MNG_APPMISCERROR : application other error"; break;
		case MNG_APPTRACEABORT:		szError = "MNG_APPTRACEABORT : application aborts on trace"; break;
		case MNG_INTERNALERROR:		szError = "MNG_INTERNALERROR : internal inconsistancy"; break;
		case MNG_INVALIDSIG:		szError = "MNG_INVALIDSIG : invalid graphics file"; break;
		case MNG_INVALIDCRC:		szError = "MNG_INVALIDCRC : crc check failed"; break;
		case MNG_INVALIDLENGTH:		szError = "MNG_INVALIDLENGTH : chunklength mystifies me"; break;
		case MNG_SEQUENCEERROR:		szError = "MNG_SEQUENCEERROR : invalid chunk sequence"; break;
		case MNG_CHUNKNOTALLOWED:	szError = "MNG_CHUNKNOTALLOWED : completely out-of-place"; break;
		case MNG_MULTIPLEERROR:		szError = "MNG_MULTIPLEERROR : only one occurence allowed"; break;
		case MNG_PLTEMISSING:		szError = "MNG_PLTEMISSING : indexed-color requires PLTE"; break;
		case MNG_IDATMISSING:		szError = "MNG_IDATMISSING : IHDR-block requires IDAT"; break;
		case MNG_CANNOTBEEMPTY:		szError = "MNG_CANNOTBEEMPTY : must contain some data"; break;
		case MNG_GLOBALLENGTHERR:	szError = "MNG_GLOBALLENGTHERR : global data incorrect"; break;
		case MNG_INVALIDBITDEPTH:	szError = "MNG_INVALIDBITDEPTH : bitdepth out-of-range"; break;
		case MNG_INVALIDCOLORTYPE:	szError = "MNG_INVALIDCOLORTYPE : colortype out-of-range"; break;
		case MNG_INVALIDCOMPRESS:	szError = "MNG_INVALIDCOMPRESS : compression method invalid"; break;
		case MNG_INVALIDFILTER:		szError = "MNG_INVALIDFILTER : filter method invalid"; break;
		case MNG_INVALIDINTERLACE:	szError = "MNG_INVALIDINTERLACE : interlace method invalid"; break;
		case MNG_NOTENOUGHIDAT:		szError = "MNG_NOTENOUGHIDAT : ran out of compressed data"; break;
		case MNG_PLTEINDEXERROR:	szError = "MNG_PLTEINDEXERROR : palette-index out-of-range"; break;
		case MNG_NULLNOTFOUND:		szError = "MNG_NULLNOTFOUND : couldn't find null-separator"; break;
		case MNG_KEYWORDNULL:		szError = "MNG_KEYWORDNULL : keyword cannot be empty"; break;
		case MNG_OBJECTUNKNOWN:		szError = "MNG_OBJECTUNKNOWN : the object can't be found"; break;
		case MNG_OBJECTEXISTS:		szError = "MNG_OBJECTEXISTS : the object already exists"; break;
		case MNG_TOOMUCHIDAT:		szError = "MNG_TOOMUCHIDAT : got too much compressed data"; break;
		case MNG_INVSAMPLEDEPTH:	szError = "MNG_INVSAMPLEDEPTH : sampledepth out-of-range"; break;
		case MNG_INVOFFSETSIZE:		szError = "MNG_INVOFFSETSIZE : invalid offset-size"; break;
		case MNG_INVENTRYTYPE:		szError = "MNG_INVENTRYTYPE : invalid entry-type"; break;
		case MNG_ENDWITHNULL:		szError = "MNG_ENDWITHNULL : may not end with NULL"; break;
		case MNG_INVIMAGETYPE:		szError = "MNG_INVIMAGETYPE : invalid image_type"; break;
		case MNG_INVDELTATYPE:		szError = "MNG_INVDELTATYPE : invalid delta_type"; break;
		case MNG_INVALIDINDEX:		szError = "MNG_INVALIDINDEX : index-value invalid"; break;
		case MNG_TOOMUCHJDAT:		szError = "MNG_TOOMUCHJDAT : got too much compressed data"; break;
		case MNG_JPEGPARMSERR:		szError = "MNG_JPEGPARMSERR : JHDR/JPEG parms do not match"; break;
		case MNG_INVFILLMETHOD:		szError = "MNG_INVFILLMETHOD : invalid fill_method"; break;
		case MNG_OBJNOTCONCRETE:	szError = "MNG_OBJNOTCONCRETE : object must be concrete"; break;
		case MNG_TARGETNOALPHA:		szError = "MNG_TARGETNOALPHA : object has no alpha-channel"; break;
		case MNG_MNGTOOCOMPLEX:		szError = "MNG_MNGTOOCOMPLEX : can't handle complexity"; break;
		case MNG_UNKNOWNCRITICAL:	szError = "MNG_UNKNOWNCRITICAL : unknown critical chunk found"; break;
		case MNG_UNSUPPORTEDNEED:	szError = "MNG_UNSUPPORTEDNEED : nEED requirement unsupported"; break;
		case MNG_INVALIDDELTA:		szError = "MNG_INVALIDDELTA : Delta operation illegal"; break;
		case MNG_INVALIDMETHOD:		szError = "MNG_INVALIDMETHOD : invalid MAGN method"; break;
		case MNG_IMPROBABLELENGTH:	szError = "MNG_IMPROBABLELENGTH : impropable chunk length"; break;
		case MNG_INVALIDBLOCK:		szError = "MNG_INVALIDBLOCK : invalid delta block"; break;
		case MNG_INVALIDEVENT:		szError = "MNG_INVALIDEVENT : invalid event_type"; break;
		case MNG_INVALIDMASK:		szError = "MNG_INVALIDMASK : invalid mask_type"; break;
		case MNG_NOMATCHINGLOOP:	szError = "MNG_NOMATCHINGLOOP : ENDL without matching LOOP"; break;
		case MNG_SEEKNOTFOUND:		szError = "MNG_SEEKNOTFOUND : EvNT points to unknown SEEK"; break;
		case MNG_OBJNOTABSTRACT:	szError = "MNG_OBJNOTABSTRACT : object must be abstract"; break;
		case MNG_TERMSEQERROR:		szError = "MNG_TERMSEQERROR : TERM in wrong place"; break;
		case MNG_INVALIDFIELDVAL:	szError = "MNG_INVALIDFIELDVAL : invalid fieldvalue (generic)"; break;
		case MNG_INVALIDCNVSTYLE:	szError = "MNG_INVALIDCNVSTYLE : can't make anything of this"; break;
		case MNG_WRONGCHUNK:		szError = "MNG_WRONGCHUNK : accessing the wrong chunk"; break;
		case MNG_INVALIDENTRYIX:	szError = "MNG_INVALIDENTRYIX : accessing the wrong entry"; break;
		case MNG_NOHEADER:			szError = "MNG_NOHEADER : must have had header first"; break;
		case MNG_NOCORRCHUNK:		szError = "MNG_NOCORRCHUNK : can't find parent chunk"; break;
		case MNG_NOMHDR:			szError = "MNG_NOMHDR : no MNG header available"; break;
		case MNG_IMAGETOOLARGE:		szError = "MNG_IMAGETOOLARGE : input-image way too big"; break;
		case MNG_NOTANANIMATION:	szError = "MNG_NOTANANIMATION : file not a MNG"; break;
		case MNG_FRAMENRTOOHIGH:	szError = "MNG_FRAMENRTOOHIGH : frame-nr out-of-range"; break;
		case MNG_LAYERNRTOOHIGH:	szError = "MNG_LAYERNRTOOHIGH : layer-nr out-of-range"; break;
		case MNG_PLAYTIMETOOHIGH:	szError = "MNG_PLAYTIMETOOHIGH : playtime out-of-range"; break;
		case MNG_FNNOTIMPLEMENTED:	szError = "MNG_FNNOTIMPLEMENTED : function not yet available"; break;
		case MNG_IMAGEFROZEN:		szError = "MNG_IMAGEFROZEN : stopped displaying"; break;
		}

		printf("\nMNG Error : %s\n", szError);
		return 1;
	}
	else
		return 0;
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
mng_ptr my_alloc(mng_size_t _iSize)
{
	/*~~~~~~~~~~~~~~*/
	mng_ptr pvPointer;
	/*~~~~~~~~~~~~~~*/

	pvPointer = malloc(_iSize);
	if(pvPointer) memset(pvPointer, 0, _iSize);
	return pvPointer;
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void my_free(mng_ptr _pvPointer, mng_size_t _iSize)
{
	free(_pvPointer);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
mng_bool my_readdata(mng_handle _hHandle, mng_ptr _pBuf, mng_uint32 _iBuflen, mng_uint32p _pRead)
{
	*_pRead = (mng_uint32) fread(_pBuf, 1, _iBuflen, g_poMNGFile);
	return MNG_TRUE;
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
mng_bool my_open_stream(mng_handle)
{
	g_poMNGFile = fopen(g_pcMNGFileName, "rb");
	if(g_poMNGFile)
		return MNG_TRUE;
	else
		return MNG_FALSE;
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
mng_bool my_close_stream(mng_handle)
{
	fclose(g_poMNGFile);
	g_poMNGFile = 0;
	return MNG_TRUE;
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
mng_bool my_processheader(mng_handle _hHandle, mng_uint32 _iWidth, mng_uint32 _iHeight)
{
	/*~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
	mng_bool	bResult = MNG_TRUE;
	/*~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

	g_uiImageWidth = _iWidth;
	g_uiImageHeight = _iHeight;

	g_uiRefreshRate = mng_get_ticks(_hHandle);
	g_uiTimer = 0;
	g_uiFrame = 0;

	g_pcCanvas0 = (unsigned char *) malloc(g_uiImageHeight * g_uiImageWidth * 4);
	if(!g_pcCanvas0) return MNG_FALSE;

	g_pcCanvas1 = (unsigned char *) malloc(g_uiImageHeight * g_uiImageWidth * 4);
	if(!g_pcCanvas1) return MNG_FALSE;

	if(g_bResample)
	{
		g_pcResampledCanvas = (unsigned char *) malloc(g_uiCanvasHeight * g_uiCanvasWidth * 4);
		if(!g_pcResampledCanvas) return MNG_FALSE;
		memset(g_pcResampledCanvas, 0, g_uiCanvasHeight * g_uiCanvasWidth * 4);
		g_poSrc = new VBitmap(g_pcCanvas0, g_uiImageWidth, g_uiImageHeight, 32);
		g_poDst = new VBitmap(g_pcResampledCanvas, g_uiCanvasWidth, g_uiCanvasHeight, 32);

		g_oResampler.Init
			(
				g_eFilter,
				g_eFilter,
				g_uiResampledWidth,
				g_uiResampledHeight,
				g_uiImageWidth,
				g_uiImageHeight
			);
	}
	else
	{
		g_uiCanvasWidth = g_uiImageWidth;
		g_uiCanvasHeight = g_uiImageHeight;
	}

	g_pcCurrentCanvas = g_pcCanvas0;

	printf("%s is %dx%d at %dfps\n\n", g_pcMNGFileName, g_uiImageWidth, g_uiImageHeight, g_uiRefreshRate);
	printf("Processing Frame #       ");

	if
	(
		!bStartRecording
			(
				g_uiCanvasWidth,
				g_uiCanvasHeight,
				g_uiRefreshRate / (g_eMode == e_FULL ? 1 : 2),
				g_pcAVIFileName,
				g_acCodec,
				g_bConfig
			)
	) return MNG_FALSE;
	else
		return MNG_TRUE;
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
mng_bool my_imagerefresh(mng_handle _hHandle, mng_uint32 iX, mng_uint32 iY, mng_uint32 iWidth, mng_uint32 iHeight)
{
	/*~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
	mng_bool	bResult = MNG_TRUE;
	/*~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

	printf("\b\b\b\b\b\b\b%7d", g_uiFrame);

	if(g_eMode == e_FULL)
	{
		if(g_bResample)
		{
			g_oResampler.Process
				(
					g_poDst,
					(g_uiCanvasWidth - g_uiResampledWidth) / 2,
					(g_uiCanvasHeight - g_uiResampledHeight) / 2,
					g_poSrc,
					0,
					0,
					0
				);
			if(!bRecord(g_pcResampledCanvas, g_uiFrame++)) bResult = MNG_FALSE;
		}
		else if(!bRecord(g_pcCanvas0, g_uiFrame++))
			bResult = MNG_FALSE;
	}
	else
	{
		if(g_pcCurrentCanvas == g_pcCanvas1)
		{
			if(g_eMode == e_INTERPOLATED)
			{
				/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
				unsigned int	iR;
				unsigned char	*pSrc, *pDst, *pEnd;
				/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

				pEnd = g_pcCanvas0 + g_uiImageWidth * g_uiImageHeight * 4;

				for(pSrc = g_pcCanvas0, pDst = g_pcCanvas1; pSrc < pEnd; pSrc++, pDst++)
				{
					iR = (*pSrc +*pDst + 1) / 2;
					*pSrc = iR;
				}
			}

			g_pcCurrentCanvas = g_pcCanvas0;

			if(g_bResample)
			{
				g_oResampler.Process
					(
						g_poDst,
						(g_uiCanvasWidth - g_uiResampledWidth) / 2,
						(g_uiCanvasHeight - g_uiResampledHeight) / 2,
						g_poSrc,
						0,
						0,
						0
					);
				if(!bRecord(g_pcResampledCanvas, g_uiFrame++)) bResult = MNG_FALSE;
			}
			else if(!bRecord(g_pcCanvas0, g_uiFrame++))
				bResult = MNG_FALSE;
		}
		else
		{
			g_pcCurrentCanvas = g_pcCanvas1;
		}
	}

	return bResult;
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
mng_ptr my_getcanvasline(mng_handle, mng_uint32 _uiLine)
{
	return g_pcCurrentCanvas + (g_uiImageHeight - _uiLine - 1) * g_uiImageWidth * 4;
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
mng_uint32 my_gettickcount(mng_handle _hHandle)
{
	return g_uiTimer;
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
mng_bool my_settimer(mng_handle _hHandle, mng_uint32 _iMsecs)
{
	g_uiTimer += _iMsecs;
	return MNG_TRUE;
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
int bParseArguments(int argc, char **argv)
{
	/*~~~~~~~~~~~~~~~~~~~*/
	int iI, iArgumentIndex;
	/*~~~~~~~~~~~~~~~~~~~*/

	iArgumentIndex = 0;
	for(iI = 1; iI < argc; iI++)
	{
		if(strnicmp(argv[iI], "/frames:", 8) == 0)
		{
			if(stricmp(argv[iI] + 8, "full") == 0)
				g_eMode = e_FULL;
			else if(stricmp(argv[iI] + 8, "decimated") == 0)
				g_eMode = e_DECIMATED;
			else if(stricmp(argv[iI] + 8, "interpolated") == 0)
				g_eMode = e_INTERPOLATED;
			else
				return 0;
		}
		else if(strnicmp(argv[iI], "/resize:", 8) == 0)
		{
			/*~~~~~~~~~*/
			int iScanned;
			/*~~~~~~~~~*/

			iScanned = sscanf
				(
					argv[iI] + 8,
					"%dx%d:%dx%d",
					&g_uiResampledWidth,
					&g_uiResampledHeight,
					&g_uiCanvasWidth,
					&g_uiCanvasHeight
				);
			if(iScanned == 2)
			{
				g_bResample = 1;
				g_uiCanvasWidth = g_uiResampledWidth;
				g_uiCanvasHeight = g_uiResampledHeight;
			}
			else if(iScanned == 4)
			{
				g_bResample = 1;
			}
			else
				return 0;
		}
		else if(strnicmp(argv[iI], "/filter:", 8) == 0)
		{
			if(sscanf(argv[iI] + 8, "%d", &g_eFilter) != 1)
				return 0;
			else if((g_eFilter < 0) || (g_eFilter > 8))
				return 0;
		}
		else if(strnicmp(argv[iI], "/codec:", 7) == 0)
		{
			memset(g_acCodec, 0, 4);
			strncpy(g_acCodec, argv[iI] + 7, 4);
		}
		else if(strnicmp(argv[iI], "/config", 7) == 0)
		{
			g_bConfig = 1;
		}
		else
		{
			if(argv[iI][0] == '/') return 0;

			if(iArgumentIndex == 0)
				g_pcMNGFileName = argv[iI];
			else if(iArgumentIndex == 1)
				g_pcAVIFileName = argv[iI];
			else
				return 0;

			iArgumentIndex++;
		}
	}

	return(g_pcMNGFileName && g_pcAVIFileName);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
int main(int argc, char **argv)
{
	/*~~~~~~~~~~~~~~~~~~~~*/
	mng_handle	myhandle;
	mng_retcode retcode;
	int			iResult = 0;
	/*~~~~~~~~~~~~~~~~~~~~*/

	printf("MNG2AVI 1.1 by Louthrax\n");

	if(!bParseArguments(argc, argv))
	{
		printf("\
Usage : MNG2AVI <mng_file> <avi_file> [options]\n\
[options] are:\n\
\t/frames:<full|interpolated|decimated>\n\
\t/resize:<width>x<height>[:<canvas_width>x<canvas_height>]\n\
\t/codec:<fourcc> (defaults to xvid)\n\
\t/config\n\
\t/filter:<0-8>\n\
\t\t0: Point\n\
\t\t1: Linear interpolation\n\
\t\t2: Cubic interpolation (default)\n\
\t\t3: Cubic interpolation 0.60\n\
\t\t4: Linear decimate\n\
\t\t5: Cubic decimate 0.75\n\
\t\t6: Cubic decimate 0.60\n\
\t\t7: Cubic decimate 1.00\n\
\t\t8: Lanczos3\n");
		iResult = 1;
	}
	else
	{
		CPUCheckForExtensions();
		CPUEnableExtensions(0xFF);
		myhandle = mng_initialize(0, my_alloc, my_free, MNG_NULL);

		mng_setcb_openstream(myhandle, my_open_stream);
		mng_setcb_readdata(myhandle, my_readdata);
		mng_setcb_closestream(myhandle, my_close_stream);
		mng_setcb_getcanvasline(myhandle, my_getcanvasline);
		mng_setcb_processheader(myhandle, my_processheader);
		mng_setcb_refresh(myhandle, my_imagerefresh);
		mng_setcb_gettickcount(myhandle, my_gettickcount);
		mng_setcb_settimer(myhandle, my_settimer);

		mng_set_canvasstyle(myhandle, MNG_CANVAS_BGRA8);
		mng_set_cacheplayback(myhandle, MNG_FALSE);
		mng_set_doprogressive(myhandle, MNG_FALSE);

		retcode = mng_readdisplay(myhandle);
		if(retcode == MNG_NEEDTIMERWAIT)
		{
			while(retcode == MNG_NEEDTIMERWAIT) retcode = mng_display_resume(myhandle);
			if(bMNGError(retcode)) iResult = 1;
			mng_cleanup(&myhandle);
			vStopRecording();
		}
		else
		{
			bMNGError(retcode);
			iResult = 1;
		}
	}

	if(iResult == 0)
	{
		/*~~~~~~~~~*/
		int iDivisor;
		/*~~~~~~~~~*/

		iDivisor = g_uiFrame * 125 / (g_uiRefreshRate / (g_eMode == e_FULL ? 1 : 2));
		printf("\n\nAverage kpbs : %d\nOK.\n", g_iBytesWritten / iDivisor);
	}

	if(g_pcCanvas0) free(g_pcCanvas0);
	if(g_pcCanvas1) free(g_pcCanvas1);
	if(g_pcResampledCanvas) free(g_pcResampledCanvas);
	return iResult;
}
